﻿using System;
using System.Web;
using System.Data.SqlClient;
using System.Collections.Specialized;
using System.Configuration;
using System.Web.Configuration;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Configuration.Provider;
using System.Security.Permissions;
using System.Data;
using System.Data.Common;

namespace Commerce.Base.Web.SiteMap
{
    /// An extremely simple AccessSiteMapProvider that only supports a
    /// site map node hierarchy 1 level deep.
    [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal)]
    public class SiteMapProvider : StaticSiteMapProvider
    {
        private System.Web.SiteMapNode rootNode = null;
        private SqlConnection connection = null;

        // Implement a default constructor.
        public SiteMapProvider() { }

        // Some basic state to help track the initialization state of the provider.
        private bool initialized = false;
        public virtual bool IsInitialized
        {
            get
            {
                return initialized;
            }
        }
        // Return the root node of the current site map.
        public override System.Web.SiteMapNode RootNode
        {
            get
            {
                if (this.rootNode == null)
                    this.rootNode = BuildSiteMap();
                return this.rootNode;
            }
        }
        protected override System.Web.SiteMapNode GetRootNodeCore()
        {
            return RootNode;
        }
        // Initialize is used to initialize the properties and any state that the
        // AccessProvider holds, but is not used to build the site map.
        // The site map is built when the BuildSiteMap method is called.
        public override void Initialize(string name, NameValueCollection attributes)
        {
            if (IsInitialized)
                return;

            // Assign the provider a default name if it doesn't have one
            if (String.IsNullOrEmpty(name))
                name = "CommerceSiteMapProvider";

            base.Initialize(name, attributes);

            // Initialize _connect
            string connectionStringName = attributes["connectionStringName"];

            if (String.IsNullOrEmpty(connectionStringName))
                throw new ProviderException("Empty or missing connectionStringName");

            attributes.Remove("connectionStringName");

            if (WebConfigurationManager.ConnectionStrings[connectionStringName] == null)
                throw new ProviderException("Missing connection string");

            string connectionString = WebConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString;

            if (String.IsNullOrEmpty(connectionString))
                throw new ProviderException("Empty connection string");

            connection = new SqlConnection(connectionString);

            if (attributes["securityTrimmingEnabled"] != null)
                attributes.Remove("securityTrimmingEnabled");

            // Throw an exception if unrecognized attributes remain
            if (attributes.Count > 0)
            {
                string attribute = attributes.GetKey(0);
                if (!String.IsNullOrEmpty(attribute))
                    throw new ProviderException("Unrecognized attribute: " + attribute);
            }

            initialized = true;
        }

        ///
        /// SiteMapProvider and StaticSiteMapProvider methods that this derived class must override.
        ///
        // Clean up any collections or other state that an instance of this may hold.
        protected override void Clear()
        {
            lock (this)
            {
                rootNode = null;
                base.Clear();
            }
        }

        // Build an in-memory representation from persistent
        // storage, and return the root node of the site map.
        public override System.Web.SiteMapNode BuildSiteMap()
        {

            // Since the SiteMap class is static, make sure that it is
            // not modified while the site map is built.
            lock (this)
            {

                // If there is no initialization, this method is being
                // called out of order.
                if (!IsInitialized)
                {
                    throw new Exception("BuildSiteMap called incorrectly.");
                }

                // If there is no root node, then there is no site map.
                if (this.rootNode != null)
                    return this.rootNode;

                // Start with a clean slate
                Clear();

                if (this.connection.State == ConnectionState.Closed)
                    this.connection.Open();

                SqlCommand rootNodeCommand = new SqlCommand("SELECT Id, ParentId, Name FROM SiteMap ORDER BY ParentId", connection);
                SqlDataReader rootNodeReader = rootNodeCommand.ExecuteReader();

                if (rootNodeReader.HasRows)
                {
                    while (rootNodeReader.Read())
                    {
                        int id = rootNodeReader.GetInt32(0);
                        int parentId = -1;
                        if (!rootNodeReader.IsDBNull(1))
                            parentId = rootNodeReader.GetInt32(1);
                        string name = rootNodeReader.GetString(2);

                        
                        // Create a SiteMapNode that references the current StaticSiteMapProvider.
                        System.Web.SiteMapNode node = new System.Web.SiteMapNode(this, string.Format("Site:{0}", id), name + ".aspx", name);

                        if (parentId > -1)
                        {
                            System.Web.SiteMapNode parentNode = FindSiteMapNodeFromKey(string.Format("Site:{0}", parentId));
                            if (parentNode == null)
                                AddNode(node, rootNode);
                            else
                                AddNode(node, parentNode);
                        }
                        else
                        {
                            rootNode = node;
                        }

                    }
                }
                else return null;

                rootNodeReader.Close();

                //BuildChildNodes(rootNode);

                connection.Close();




                //SetSiteMapNodeUrl(rootNode);

                return rootNode;
            }
        }

        public SiteMapNode BuildTemporarySiteMap()
        {
            SiteMapNode rootNode = null;

            SqlCommand rootNodeCommand = new SqlCommand("SELECT Id, Name FROM SiteMap WHERE ParentId IS NULL", connection);
            SqlDataReader rootNodeReader = rootNodeCommand.ExecuteReader();

            if (rootNodeReader.HasRows && rootNodeReader.Read())
            {
                int key = rootNodeReader.GetInt32(0);
                string name = rootNodeReader.GetString(1);
                //rootNode = new SiteMapNode(null, 
            }

            
            return rootNode;
        }

        public SiteMapNode BuildTemporarySiteMapNode(SiteMapNode parentNode)
        {
            SiteMapNode node = null;
            return node;
        }

        private void SetSiteMapNodeUrl(System.Web.SiteMapNode node)
        {
            node.Url = GetNodeUrl(node);
            foreach (System.Web.SiteMapNode childNode in node.ChildNodes)
                SetSiteMapNodeUrl(childNode);
        }

        private void BuildChildNodes(System.Web.SiteMapNode parentNode)
        {
            SqlCommand sqlCommand = new SqlCommand("SELECT Id, Name FROM SiteMap WHERE ParentId = " + parentNode.Key, connection);
            SqlDataReader sqlDataReader = sqlCommand.ExecuteReader();
            DataTable table = new DataTable();
            table.Load(sqlDataReader);
            sqlDataReader.Close();

            foreach (DataRow row in table.Rows)
            {
                string id = row["Id"].ToString();
                string title = row["Name"].ToString();
                string description = "description";
                System.Web.SiteMapNode node = new System.Web.SiteMapNode(this, id, null, title, description);
                AddNode(node, parentNode);
                BuildChildNodes(node);
            }
        }

        private string GetNodeUrl(System.Web.SiteMapNode node)
        {
            string url = Base.Utilities.Url.PathEncode(node.Title);
            if (node == rootNode)
                url = Base.Utilities.Url.BaseUrl;
            else if (node.ParentNode != null && node.ParentNode != rootNode)
                url = GetNodeUrl(node.ParentNode) + "/" + url;
            else
                url = Base.Utilities.Url.BaseUrl + url;

            if (!node.HasChildNodes && node != rootNode)
                url += ".aspx";
            return url;
        }
    }
}
